import tkinter as tk
from tkinter import ttk, messagebox
import requests
from urllib.parse import urlparse
import webbrowser
import threading
import queue

# 全局变量
result_queue = queue.Queue()
stop_flag = False


# --- 核心功能 ---

def check_redirect_chain(url):
    """检测完整的重定向链"""
    try:
        headers = {'User-Agent': 'Mozilla/5.0'}
        response = requests.get(url, headers=headers, allow_redirects=True, timeout=10)

        # 收集跳转历史
        history = [{"url": h.url, "status": h.status_code, "location": h.headers.get("Location")} for h in
                   response.history]
        final_response = {"url": response.url, "status": response.status_code, "location": None}
        history.append(final_response)

        return history
    except requests.RequestException as e:
        return [{"url": url, "status": f"[网络错误: {str(e)}]", "location": None}]


# --- 多线程处理 ---

def start_processing():
    """启动处理线程"""

    # 禁用开始按钮
    start_btn.config(state=tk.DISABLED)

    # 清空残留队列数据
    while not result_queue.empty():
        try:
            result_queue.get_nowait()
        except queue.Empty:
            break

    # 清空表格
    for row in tree.get_children():
        tree.delete(row)

    # 恢复状态
    global stop_flag
    stop_flag = False

    # 创建进度标签
    processing_label.config(text="处理中... 0/0")
    processing_label.grid(row=2, column=0, sticky="ew")

    # 获取输入URL
    input_text = input_area.get("1.0", tk.END)
    urls = [line.strip() for line in input_text.splitlines() if line.strip()]
    total_urls = len(urls)

    # 创建处理线程
    def process_thread():
        try:
            for index, url in enumerate(urls):
                if stop_flag:
                    break

                # 自动添加协议
                if not urlparse(url).scheme:
                    url = f"http://{url}"

                # 执行检测
                history = check_redirect_chain(url)
                final_location = history[-1]["url"] if len(history) > 1 else "[无重定向]"
                redirect_count = len(history) - 1  # 排除最终状态码

                # 修改状态码逻辑
                if redirect_count > 0:
                    final_status = history[0]["status"]
                else:
                    final_status = history[-1]["status"]

                # 推送结果到队列
                result_queue.put({
                    "url": url,
                    "final_location": final_location,
                    "redirect_count": redirect_count,
                    "final_status": final_status,
                    "progress": f"处理中... {index + 1}/{total_urls}"
                })

            result_queue.put(None)  # 结束标记
        except Exception as e:
            result_queue.put({"error": str(e)})
        finally:
            # 确保界面更新在主线程执行
            root.after(0, lambda: start_btn.config(state=tk.NORMAL))

    # 启动线程
    threading.Thread(target=process_thread, daemon=True).start()

    # 启动队列检查
    check_queue()


def check_queue():
    """处理队列中的结果"""
    global stop_flag
    try:
        while True:
            item = result_queue.get_nowait()

            if item is None:  # 处理完成
                processing_label.grid_remove()
                return
            if "error" in item:  # 错误处理
                messagebox.showerror("错误", item["error"])
                return

            # 更新进度标签
            processing_label.config(text=item.get("progress", ""))

            # 插入表格数据
            tree.insert("", "end", values=(
                item["url"],
                item["final_status"],
                item["final_location"],
                item["redirect_count"]
            ))

            # 强制刷新界面
            tree.update_idletasks()
    except queue.Empty:
        pass

    # 继续检查队列（每50ms）
    if not stop_flag:
        root.after(50, check_queue)


def stop_processing():
    """停止处理"""
    global stop_flag
    stop_flag = True

    # 恢复按钮状态
    start_btn.config(state=tk.NORMAL)


# --- GUI 功能 ---

def on_table_click(event):
    """处理表格点击事件"""
    region = tree.identify("region", event.x, event.y)
    if region != "cell":
        return

    item = tree.identify_row(event.y)
    col = tree.identify_column(event.x)
    values = tree.item(item, "values")

    # 检查是否按下了Ctrl键
    is_ctrl_clicked = (event.state & 0x4) == 0x4  # 在某些平台上可能需要调整这个值

    # 点击操作列
    if col in ["#1", "#3"] and is_ctrl_clicked:  # 如果是Ctrl+点击原始URL或目标URL的操作列
        url = values[0] if col == "#1" else values[2]
        if is_valid_url(url):
            webbrowser.open(url)

    elif col == "#4":  # 显示跳转历史
        url = values[0]
        history = check_redirect_chain(url)
        show_redirect_history(history)


def show_redirect_history(history):
    """显示跳转历史弹窗"""
    dialog = tk.Toplevel()
    dialog.title("跳转路径详情")
    dialog.geometry("800x500")

    # 创建表格
    columns = ("步骤", "状态码", "URL")
    tree_history = ttk.Treeview(dialog, columns=columns, show="headings", selectmode="browse")

    # 设置列
    tree_history.heading("步骤", text="步骤")
    tree_history.heading("状态码", text="状态码")
    tree_history.heading("URL", text="URL")
    tree_history.column("步骤", width=60, anchor="center")
    tree_history.column("状态码", width=80, anchor="center")
    tree_history.column("URL", width=600, anchor="w")

    # 填充数据
    for idx, record in enumerate(history, 1):
        tree_history.insert("", "end", values=(idx, record["status"], record["url"]))

    tree_history.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    # 添加滚动条
    scrollbar = ttk.Scrollbar(dialog, orient="vertical", command=tree_history.yview)
    scrollbar.pack(side="right", fill="y")
    tree_history.configure(yscrollcommand=scrollbar.set)

    # 绑定点击事件
    tree_history.bind("<ButtonRelease-1>", lambda e: open_history_url(e, tree_history))


def open_history_url(event, tree_widget):
    """打开历史记录中的URL"""
    item = tree_widget.selection()[0]
    url = tree_widget.item(item, "values")[2]
    if is_valid_url(url):
        webbrowser.open(url)


def is_valid_url(url):
    """验证URL有效性"""
    try:
        result = urlparse(url)
        return all([result.scheme, result.netloc])
    except:
        return False


# --- GUI 布局 ---

root = tk.Tk()
root.title("301重定向检测工具 v4.0 - 咖啡续命又一天")
root.geometry("1000x700")

# 配置网格布局
root.grid_rowconfigure(0, weight=1)  # 表格区域
root.grid_rowconfigure(1, weight=0)  # 输入区域
root.grid_rowconfigure(2, weight=0)  # 进度条区域
root.grid_columnconfigure(0, weight=1)

# --- 表格区域 ---
table_frame = ttk.Frame(root)
table_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")

# 创建带滚动条的表格
tree = ttk.Treeview(table_frame, columns=("原始URL", "状态码", "重定向URL", "跳转次数"),
                    show="headings", selectmode="browse")

# 配置列
columns = [
    ("原始URL", 400),
    ("状态码", 60),
    ("重定向URL", 400),
    ("跳转次数", 60)
]

for col_name, width in columns:
    tree.heading(col_name, text=col_name)
    # 如果是“跳转次数”或“状态码”，则居中显示；其他列靠左显示
    anchor = "center" if col_name in ("跳转次数", "状态码") else "w"
    tree.column(col_name, width=width, anchor=anchor)

# 添加滚动条
# scrollbar = ttk.Scrollbar(table_frame, orient="vertical", command=tree.yview)
# scrollbar.pack(side="right", fill="y")
# tree.configure(yscrollcommand=scrollbar.set)
tree.pack(fill=tk.BOTH, expand=True)

# 绑定事件
tree.bind("<ButtonRelease-1>", on_table_click)

# --- 输入区域 ---
input_frame = ttk.LabelFrame(root, text="URL输入区")
input_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew")

input_area = tk.Text(input_frame, height=8, font=("微软雅黑", 10), wrap=tk.NONE)
input_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)

# 水平滚动条
input_scroll_x = ttk.Scrollbar(input_frame, orient="horizontal", command=input_area.xview)
input_scroll_x.pack(fill="x")
input_area.configure(xscrollcommand=input_scroll_x.set)

# --- 按钮区域 ---
button_frame = ttk.Frame(root)
button_frame.grid(row=1, column=0, padx=10, pady=5, sticky="se")

start_btn = ttk.Button(button_frame, text="开始检测", command=start_processing, style='Custom.TButton')
start_btn.pack(side="left", padx=5)

stop_btn = ttk.Button(button_frame, text="停止检测", command=stop_processing)
stop_btn.pack(side="left", padx=5)

# --- 进度标签 ---
processing_label = ttk.Label(root, foreground="blue", anchor="center")
processing_label.grid(row=2, column=0, sticky="ew", padx=10, pady=5)
processing_label.grid_remove()

# 启动主循环
root.mainloop()
